package com.applcn.user.service;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.applcn.core.base.Result;
import com.applcn.core.redis.RedisDisLock;
import com.applcn.message.client.SmsClient;
import com.applcn.message.dto.SendSmsCodeDTO;
import com.applcn.user.constant.RedisKeyConstants;
import com.applcn.user.dto.CreateTokenDTO;
import com.applcn.user.dto.CreateUserDTO;
import com.applcn.user.dto.merchant.CreateMerchantReqDTO;
import com.applcn.user.dto.merchant.GainSmsCodeDTO;
import com.applcn.user.dto.merchant.LoginByPhoneAndPasswordReqDTO;
import com.applcn.user.repo.entity.MerchantEntity;
import com.applcn.user.repo.entity.UserEntity;
import com.applcn.user.repo.repository.MerchantRepository;
import com.applcn.user.repo.repository.UserRepository;
import com.applcn.user.utils.JwtUtil;
import com.wf.captcha.GifCaptcha;
import com.wf.captcha.base.Captcha;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * com.applcn.user.service
 * Description:
 *
 * @author: 大妖怪
 * @date: 2020-01-21 06:55
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MerchantService {
    private final UserService userService;
    private final MerchantRepository merchantRepository;
    private final RedisDisLock redisDisLock;
    private final SmsClient smsClient;
    private final UserRepository userRepository;
    private final JwtUtil jwtUtil;

    @Value("${debugModule}")
    private Boolean debugModule;

    /**
     * 发送短信验证码
     *
     * @param uuid
     * @param response
     */
    public void captcha(String uuid, HttpServletResponse response) throws IOException {
        // 设置请求头为输出图片类型
        response.setContentType("image/gif");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        // 三个参数分别为宽、高、位数
        GifCaptcha specCaptcha = new GifCaptcha(130, 48, 4);

        redisDisLock.lock(uuid, specCaptcha.text(), 5, TimeUnit.MINUTES);

        // 设置类型，纯数字、纯字母、字母数字混合
        specCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);

        // 输出图片流
        specCaptcha.out(response.getOutputStream());
    }

    /**
     * 发送短信验证码
     *
     * @param dto
     * @return
     */
    public Result sendSmsCode(GainSmsCodeDTO dto) {
        // 校验图形验证码
        checkCode(dto.getUuid(), dto.getCode());

        String key = RedisKeyConstants.SEND_REGISTER_SMS_CODE_KEY + dto.getPhone();
        if (debugModule) {
            String smsCode = "123456";
            redisDisLock.lock(key, smsCode, 1, TimeUnit.MINUTES);
            log.info("smsCode==={}", smsCode);
        } else {
            String smsCode = RandomUtil.randomNumbers(4);
            log.info("smsCode==={}", smsCode);
            redisDisLock.lock(key, smsCode, 1, TimeUnit.MINUTES);
            SendSmsCodeDTO shopSendSmsCodeDTO = new SendSmsCodeDTO();
            shopSendSmsCodeDTO.setPhone(dto.getPhone());
            shopSendSmsCodeDTO.setCode(smsCode);
            Result result = smsClient.sendMessage(shopSendSmsCodeDTO);
            Assert.isTrue(result.isSuccess(), "获取验证码失败！");
        }
        return Result.ok();
    }

    /**
     * 创建商户
     *
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Result createMerchant(CreateMerchantReqDTO dto) {
        // 校验短信验证码
        checkSmsCode(dto.getPhone(), dto.getSmsCode());

        CreateUserDTO createUserDTO = new CreateUserDTO();
        BeanUtils.copyProperties(dto, createUserDTO);
        Result result = userService.createUserByPhoneAndPassword(createUserDTO);
        if (!result.isSuccess()) {
            return result;
        }

        Long userId = Long.parseLong(result.getData().toString());
        MerchantEntity merchantEntity = new MerchantEntity();
        merchantEntity.setUserId(userId);
        merchantRepository.save(merchantEntity);
        return Result.ok();
    }

    /**
     * 手机号密码登录
     *
     * @param dto
     * @return
     */
    public Result loginByPhoneAndPassword(LoginByPhoneAndPasswordReqDTO dto) {
        // 校验图形验证码
        checkCode(dto.getUuid(), dto.getCode());

        UserEntity userEntity = userRepository.getByPhoneAndPassword(dto.getPhone(), dto.getPassword());
        Assert.notNull(userEntity, "用户名或密码错误！");

        MerchantEntity merchantEntity = merchantRepository.getByUserId(userEntity.getId());
        Assert.notNull(merchantEntity, "商户不存在！");

        return Result.ok().putData(createToken(userEntity.getId()));
    }

    /**
     * 短信登录
     *
     * @param phone
     * @param smsCode
     * @return
     */
    public Result loginBySmsCode(String phone, String smsCode) {
        // 校验短信验证码
        checkSmsCode(phone, smsCode);

        UserEntity userEntity = userRepository.getByPhone(phone);
        Assert.notNull(userEntity, "用户不存在");

        return Result.ok().putData(createToken(userEntity.getId()));
    }

    /**
     * 校验图形验证码
     *
     * @param uuid
     * @param code
     * @return
     */
    private void checkCode(String uuid, String code) {
        String trueCode = redisDisLock.getCode(uuid);
        Assert.isTrue(StrUtil.equalsIgnoreCase(code, trueCode), "图形验证码不正确");
    }

    /**
     * 校验短信验证码
     *
     * @param phone
     * @param code
     */
    private void checkSmsCode(String phone, String code) {
        String key = RedisKeyConstants.SEND_REGISTER_SMS_CODE_KEY + phone;
        String trueCode = redisDisLock.getCode(key);
        Assert.isTrue(StrUtil.equalsIgnoreCase(code, trueCode), "短信验证码不正确");
    }

    /**
     * 创建token
     *
     * @param userId
     * @return
     */
    private String createToken(Long userId) {
        MerchantEntity merchantEntity = merchantRepository.getByUserId(userId);
        Assert.notNull(merchantEntity, "商户不存在！");

        CreateTokenDTO createTokenDTO = new CreateTokenDTO();
        createTokenDTO.setUserId(userId);
        createTokenDTO.setMerchantId(merchantEntity.getId());
        String token = jwtUtil.createToken(createTokenDTO);

        return token;
    }
}
